﻿using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK;


namespace MyRTS
{
    class scena
    {
        /// <summary>
        /// Main Nodes Qty in fbx file
        /// </summary>
        /// <param name="f"></param>
        public int MainNodeQty=0;
        public int shaderProgramHandle;

        /// <summary>
        /// Object Name List
        /// </summary>
        /// <param name="f"></param>

        public List<string> ObjecNameList = new List<string>();

        public List<Model> ModelsList=new List<Model>();
        public List<Material> Materiallist = new List<Material>();

        public int ObjectCount=0;

        public scena(fbx f,int s)
        {
            shaderProgramHandle = s;
            foreach(Node n in f.NodeList)
            {
                MainNodeQty++;
                if (n.name == "Definitions")
                {
                    ProcessDefinitions(n);
                }
                if (n.name == "Objects")
                {
                    ProcessObjects(n);
                }
            }

           
           
           
            int h = 0;
        
        }

        public void Add(fbx f)
        {
            foreach(Node n in f.NodeList)
            {
                MainNodeQty++;
                if (n.name == "Definitions")
                {
                    ProcessDefinitions(n);
                }
                if (n.name == "Objects")
                {
                    ProcessObjects(n);
                }
            }

        }

        public void ProcessDefinitions(Node n)
        {
            foreach (Node f in n.NodeList)
            {
                if (f.name=="Count")
                foreach (Property p in f.PropertyList)
                {
                    ObjectCount = Convert.ToInt32(p.Datas);
                }

                if (f.name == "ObjectType")
                {
                    foreach (Property p in f.PropertyList)
                    {
                        if (p.type == "S")
                        {
                            ObjecNameList.Add(p.Datas);
                        }
                    }
                }
            }

        }

        public void ProcessObjects(Node n)
        {

            foreach (Node m in n.NodeList)
            {
                string name = m.name;
                if (name == "Geometry"||name == "Model")
                {
                    Model model = new Model(m,shaderProgramHandle);
                 //   model.translate = new Vector3(0, 0, 0);
                    ModelsList.Add(model);
                }
                if (name == "Material" )
                {
                    Material mat = new Material(m);
                    Materiallist.Add(mat);
                  
                }
            }

        }
    }

    public class Model
    {
        public Vector3 translate=new Vector3(0,0,0);
        public float yangle = 0;
        public float xangle = 0;
        public float zangle = 0;
        public string name = "";
        public struct VertexINFO
        {
            public Vector3 position;
            public Vector3 Normal;
            public Vector2 Texturecord;
            public Vector4 Color;
            

        }

        public VertexINFO[] Vertices;
        public int bufforNo;
        public int vaobuffor;
        private List<int> VertexIndex = new List<int>();
        private List<int> UVIndex = new List<int>();
        private List<Vector3> Vertexy = new List<Vector3>();
        private List<Vector3> Normals = new List<Vector3>();
        private List<Vector2> UVs = new List<Vector2>();

        public List<string> propertiesname = new List<string>();
        public List<string[]> Properties = new List<string[]>();

        public Vector3[] Vertexs;
        public int[] vertexIndex;
        public Vector3[] Normalss;
        public Vector2[] Textcords;

        
            public int vaoHandle;
            public int positionVboHandle;
            public int normalVboHandle;
            public int eboHandle;

            public int shaderProgramHandle;

        public string meshtype;

        public Model(Node n,int s)
        {
            shaderProgramHandle = s;
            if (n.PropertyList[0].type == "S")
            {
                this.name=n.PropertyList[0].Datas;
            }
            foreach (Node m in n.NodeList)
            {
                if (m.name == "PolygonVertexIndex")
                {
                    VertexIndex = processIndex(m);               
                }

               
                    if (m.name.Contains("Properties"))
                    {
                        foreach (Node k in m.NodeList)
                        {
                            try
                            {
                                string[] kl = new string[k.PropertyList.Count];
                                int i = 0;
                                foreach (Property p1 in k.PropertyList)
                                {
                                    kl[i] = p1.Datas;
                                    i++;
                                }
                                Properties.Add(kl);
                            }
                            catch
                            {
                            }
                        }
                        PocessProperties(m);
                    }
                    
                

                if (m.name == "Vertices")
                {
                    Vertexy = processVertex(m);
                }
                if (m.name == "LayerElementNormal")
                {
                    foreach (Node k in m.NodeList)
                    {
                        if (k.name == "Normals")
                        {
                            Normals = processVertex(k);
                        }
                    }
                }
                if (m.name == "LayerElementUV")
                {
                    foreach (Node k in m.NodeList)
                    {
                        if (k.name == "UV")
                        {
                            UVs = processUV(k);
                        }
                        if (k.name == "UVIndex")
                        {
                            UVIndex = processIndex(k);   
                        }
                    }
                }
            }
            polaczwszystko();

            int u = 0;
        }
        private List<int> processIndex(Node n)
        {
            List<int> lista = new List<int>();

            if (n.PropertyList[0].type == "i" )
            {

                byte[] data = n.PropertyList[0].Data;
                int lik = 0;
                for (int i = 0; i < data.Length; i = i + 4)
                {
                    byte[] temp = new byte[4];
                    temp[0] = data[i];
                    temp[1]=data[i+1];
                    temp[2]=data[i+2];
                    temp[3]=data[i+3];
                    int t = BitConverter.ToInt32(temp, 0);
                    lik++;
                    if (t < 0)
                    {
                        t = -(t + 1);
                        if (lik == 3)
                        {
                            meshtype = "Triangle";
                        }
                        if (lik == 4)
                        {
                            meshtype = "Quads";
                        }
                        lik = 0;
                    }
                    lista.Add(t);
                 
                }
           

            }
            else
            {
                List<int> temlist = new List<int>();
                foreach (Property p in n.PropertyList)
                {
                    if (p.type == "I")
                    {

                        int d = BitConverter.ToInt32(p.Data, 0);
                        if (d < 0)
                        {
                            d = -(d + 1);
                        }
                        lista.Add(d);
                    }

                }

               
                int u = 0;

            }
           


            return lista;
        }

        private List<Vector3> processVertex(Node n)
        {
            List<Vector3> lista = new List<Vector3>();


            if (n.PropertyList[0].type == "d")
            {

                byte[] data = n.PropertyList[0].Data;
                int lic = 0;
                float[] temf = new float[3];
                for (int i = 0; i < data.Length; i = i + 8)
                {
                    byte[] tem = new byte[8];
                    for (int j = 0; j < 8; j++)
                    {
                        tem[j] = data[i + j];
                    }
                    double d = BitConverter.ToDouble(tem, 0);
                    temf[lic] = (float)d;

                    lic++;
                    if (lic == 3)
                    {
                        Vector3 t = new Vector3(temf[0], temf[1], temf[2]);
                        lista.Add(t);
                        lic = 0;
                    }


                }
                int u = 0;
            }
            else
            {
                List<double> temlist = new List<double>();
                foreach (Property p in n.PropertyList)
                {
                    if (p.type == "D")
                    {

                        double d = BitConverter.ToDouble(p.Data, 0);
                        temlist.Add(d);
                    }

                }

                for (int i = 0; i < temlist.Count; i = i + 3)
                {
                    Vector3 te = new Vector3((float)temlist[i], (float)temlist[i + 1], (float)temlist[i + 2]);
                    lista.Add(te);
                }
                int u = 0;

            }
           

            return lista;
         
        }

        private List<Vector2> processUV(Node n)
        {
            List<Vector2> lista = new List<Vector2>();


            if (n.PropertyList[0].type == "d")
            {

                byte[] data = n.PropertyList[0].Data;
                int lic = 0;
                float[] temf = new float[3];
                for (int i = 0; i < data.Length; i = i + 8)
                {
                    byte[] tem = new byte[8];
                    for (int j = 0; j < 8; j++)
                    {
                        tem[j] = data[i + j];
                    }
                    double d = BitConverter.ToDouble(tem, 0);
                    temf[lic] = (float)d;

                    lic++;
                    if (lic == 2)
                    {
                        Vector2 t = new Vector2(temf[0], temf[1]);
                        lista.Add(t);
                        lic = 0;
                    }


                }
                int u = 0;
            }

            return lista;

        }

        private void PocessProperties(Node m)
        {
            foreach (Node p in m.NodeList)
            {
                string s = p.name;
                try
                {
                    if (p.PropertyList[0].Datas == "Lcl Translation")
                    {
                        int u = 0;
                        double[] trans = new double[3];
                        int j = 0;
                        for (int i = 0; i < p.PropertyList.Count; i++)
                        {
                            if (p.PropertyList[i].type == "D")
                            {
                                trans[j] = Convert.ToDouble(p.PropertyList[i].Datas);
                                j++;
                            }

                        }
                       this.translate=new Vector3((float)trans[0],(float)trans[1],(float)trans[2]);
                    }
                    if (p.PropertyList[0].Datas == "Lcl Rotation")
                    {
                        int u = 0;
                        double[] trans = new double[3];
                        int j = 0;
                        for (int i = 0; i < p.PropertyList.Count; i++)
                        {
                            if (p.PropertyList[i].type == "D")
                            {
                                trans[j] = Convert.ToDouble(p.PropertyList[i].Datas);
                                j++;
                            }

                        }
                        yangle = (float)trans[1];
                        xangle = (float)trans[0];
                        zangle = (float)trans[2];
                        int opp = 0;
                       // this.translate = new Vector3((float)trans[0], (float)trans[1], (float)trans[2]);
                    }
 


                }
                catch
                {

                }
                try
                {
                    string name = "";
                   
                    foreach (Property pp in p.PropertyList)
                    {
                        name += pp.Datas+"  ";       
                    }
                    
                        propertiesname.Add(name);
                    
                }
                catch
                {
                }
              
            }
        }
        
        private void polaczwszystko()
        {
          
            Vertexs = Vertexy.ToArray();
            vertexIndex=VertexIndex.ToArray();
            Normalss = Normals.ToArray();
            Textcords = UVs.ToArray();


            createbuffors();
            int p = 0;

                 
        }

        private void createbuffors()
        {
            GL.GenBuffers(1, out positionVboHandle);
            GL.BindBuffer(BufferTarget.ArrayBuffer, positionVboHandle);
            GL.BufferData<Vector3>(BufferTarget.ArrayBuffer,
                new IntPtr(Vertexs.Length * Vector3.SizeInBytes),
                Vertexs, BufferUsageHint.StaticDraw);

            GL.GenBuffers(1, out normalVboHandle);
            GL.BindBuffer(BufferTarget.ArrayBuffer, normalVboHandle);


                    // Dirty solutions to normals
            if (Normalss.Length == Vertexs.Length)
            {
                      GL.BufferData<Vector3>(BufferTarget.ArrayBuffer,
                        new IntPtr(Normalss.Length * Vector3.SizeInBytes),
                        Normalss, BufferUsageHint.StaticDraw);
            }
            else
            {

                GL.BufferData<Vector3>(BufferTarget.ArrayBuffer,
                   new IntPtr(Vertexs.Length * Vector3.SizeInBytes),
                    Vertexs, BufferUsageHint.StaticDraw);
            }

            GL.GenBuffers(1, out eboHandle);
            GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle);
            GL.BufferData(BufferTarget.ElementArrayBuffer,
                new IntPtr(sizeof(uint) * vertexIndex.Length),
                vertexIndex, BufferUsageHint.StaticDraw);

            GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
            GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);

            //VAO
            // GL3 allows us to store the vertex layout in a "vertex array object" (VAO).
            // This means we do not have to re-issue VertexAttribPointer calls
            // every time we try to use a different vertex layout - these calls are
            // stored in the VAO so we simply need to bind the correct VAO.
            GL.GenVertexArrays(1, out vaoHandle);
            GL.BindVertexArray(vaoHandle);

            GL.EnableVertexAttribArray(0);
            GL.BindBuffer(BufferTarget.ArrayBuffer, positionVboHandle);
            GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, true, Vector3.SizeInBytes, 0);
            GL.BindAttribLocation(shaderProgramHandle, 0, "in_position");

            GL.EnableVertexAttribArray(1);
            GL.BindBuffer(BufferTarget.ArrayBuffer, normalVboHandle);
            GL.VertexAttribPointer(1, 3, VertexAttribPointerType.Float, true, Vector3.SizeInBytes, 0);
            GL.BindAttribLocation(shaderProgramHandle, 1, "in_normal");

            GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle);

            GL.BindVertexArray(0);

        }


    }

    public class Material
    {
        public string name = "";
        public string shadingmodel = "";
        public List<string[]> Properties = new List<string[]>();
        public Material(Node m)
        {
            name = m.PropertyList[0].Datas;
            foreach (Node n in m.NodeList)
            {
                if (n.name == "ShadingModel")
                {
                    shadingmodel = n.PropertyList[0].Datas;
                }
                if (n.name.Contains("Properties"))
                {
                    foreach (Node k in n.NodeList)
                    {
                        try
                        {
                            string[] kl = new string[k.PropertyList.Count];
                            int i=0;
                            foreach (Property p in k.PropertyList)
                            {
                                kl[i] = p.Datas;
                                i++;
                            }
                            Properties.Add(kl);
                        }
                        catch
                        {
                        }
                    }
                }
            }
        }
    }


}
